package miniworld;

import homeMadeExceptions.ScatterNet_HostCannotJoinException;
import homeMadeExceptions.ScatterNet_HostCannotRemoveException;
import homeMadeExceptions.ScatterNet_HostIsAlreadyMasterException;

import java.util.HashMap;
import java.util.Vector;

import datatypes.Host;
import datatypes.HostDescription;
import datatypes.PicoNet;


public class ScatterNet {

	private Vector<PicoNet> piconetList = new Vector<PicoNet>();
	private Miniworld parent;
	private HashMap<String, Vector<PicoNet>> affiliation = new HashMap<String, Vector<PicoNet>>();
	private HashMap<String, Integer> activityIndex = new HashMap<String, Integer>();
	
	
	//Constructor
	public ScatterNet(Miniworld theParent){
		parent = theParent;
	}
	
	//if an node is in more than on piconets active, it must switch between 
	//two nets
	public void changeActivity(String bd_addr){
		int elem = affiliation.get(bd_addr).size();
		if ( elem > 1){
			int tmp = activityIndex.get(bd_addr);
			tmp++;
			tmp = tmp % elem;
			activityIndex.remove(bd_addr);
			activityIndex.put(bd_addr, tmp);
		}
	}
	
	//API for Building an Scatternet
	public Vector<PicoNet> getPossiblePiconetsForHost(HostDescription host){
		if (piconetList == null || piconetList.size() == 0){
			return null;
		}
		Vector<PicoNet> backList = new Vector<PicoNet>();
		for (int i = 0; i < piconetList.size(); i++){
			if (piconetList.get(i).isPossibleMember(host.getX(), host.getY())){
				backList.add(piconetList.get(i));
			}
		}
		return backList;
	}
	
	private void addHostToPiconet (HostDescription host, int PiconetId) throws ScatterNet_HostCannotJoinException{
		boolean isNotAdded = true;
		int i = 0;
		while (isNotAdded && i < piconetList.size()){
			if (piconetList.get(i).getPiconetId() == PiconetId){
				if(!piconetList.get(i).join(host)){
					throw new ScatterNet_HostCannotJoinException("Host is not a possible Member of this PicoNet");
				}
				isNotAdded = false;
			}
			i++;
		}
	}
	
	public void addSlaveToMaster (HostDescription slave, int MasterID) throws ScatterNet_HostCannotJoinException{
		boolean isNotAdded = true;
		int i = 0;
		while (isNotAdded && i < piconetList.size()){
			if (piconetList.get(i).isPossibleMember(slave.getX(), slave.getY()) && piconetList.get(i).getMaster().getHost().getID() == MasterID){
				if(!piconetList.get(i).join(slave)){
					throw new ScatterNet_HostCannotJoinException("Host is not a possible Member of this PicoNet");
				}
				isNotAdded = false;
			}
			i++;
		}
	}
	
	private void removeHostFromPiconet(Host host, int PiconetID) throws ScatterNet_HostCannotRemoveException{
		boolean isNotRemoved = true;
		int i = 0;
		while (isNotRemoved && i < piconetList.size()){
			if (piconetList.get(i).getPiconetId() == PiconetID){
				if(!piconetList.get(i).quitMembership(host.getID())){
					throw new ScatterNet_HostCannotRemoveException("Host is probably not a Member of this PicoNet");
				}
				isNotRemoved = false;
			}
			i++;
		}
	}

	private void removeHostFromNetwork(int hostID) {
		int i = 0;
		while (i < piconetList.size()){
				piconetList.get(i).quitMembership(hostID);
			i++;
		}
	}

	public void foundNewPiconet (HostDescription host, int maxMember) throws ScatterNet_HostIsAlreadyMasterException {
		boolean isNotAlreadyMaster = true;
		for (int i=0; i < piconetList.size(); i++){
			if (piconetList.get(i).isMaster(host.getHost().getID())){
				isNotAlreadyMaster = false;
			}
		}
		if (isNotAlreadyMaster){
			piconetList.add(new PicoNet(this.parent.getRoster().getRange()));
			piconetList.lastElement().launchPiconet(host, maxMember);
			if (affiliation.get(host.getHost().getBd_Addr().getAddress())== null){
				affiliation.put(host.getHost().getBd_Addr().getAddress(), new Vector<PicoNet>());
			}
			affiliation.get(host.getHost().getBd_Addr().getAddress()).add(piconetList.lastElement());				
		} else {
			throw new ScatterNet_HostIsAlreadyMasterException();
		}
	}
	
	public Vector<HostDescription> getMastersInRange(int posx, int posy){
		Vector<HostDescription> tmp = new Vector<HostDescription>();
		for (int i=0; i < piconetList.size() ; i++ ){
			if (piconetList.get(i).isPossibleMember(posx, posy)){
				tmp.add(piconetList.get(i).getMaster());
			}
		}
		return tmp;
	}
	
	public Vector<PicoNet> getPossiblePiconets (int posx, int posy){
		Vector<PicoNet> tmp = new Vector<PicoNet>();
		for (int i=0; i < piconetList.size() ; i++ ){
			if (piconetList.get(i).isPossibleMember(posx, posy)){
				tmp.add(piconetList.get(i));
			}
		}
		return tmp;
	}

	public boolean isHostAlreadyMaster(Host host){
		for (int i=0; i < piconetList.size() ; i++ ){
			if (piconetList.get(i).isMaster(host.getID())){
				return true;
			}
		}
		return false;
	}
		
	public void setDeviceDisabled(int hostID){
		this.removeHostFromNetwork(hostID);
	}
	
	public Vector<Host> getDevicesInRange (int hostID){
		return parent.getRoster().getHostsInRange(hostID);
	}
	
	public boolean isRecvMessgPossible(String sender, String receiver){
//		int s = this.activityIndex.get(sender);
//		int r = this.activityIndex.get(receiver);
//		s = this.affiliation.get(sender).get(s).getPiconetId();
//		r = this.affiliation.get(receiver).get(r).getPiconetId();
		return true ;//s == r;
	}
}
